<template>
  <el-dialog
    :title="`JSON格式化工具`"
    v-model="drawerVisible"
    :draggable="true"
    :overflow="true"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    top="30px"
    width="80%"
    :destroy-on-close="true"
    :z-index="2000"
  >
    <el-form ref="ruleFormRef" style="overflow-y: auto" label-width="120px" label-position="left">
      <div class="json-formatter-form">
        <!-- 输入区域 -->
        <div class="input-section">
          <h3 class="section-title">
            <el-icon><EditPen /></el-icon>
            JSON输入
          </h3>
          <div class="input-container">
            <el-input
              type="textarea"
              :rows="12"
              placeholder="请输入JSON字符串..."
              v-model="inputJson"
              :maxlength="maxLength"
              show-word-limit
              @input="onInputChange"
            />
            <div class="input-info">
              <span class="char-count">字符数: {{ inputJson.length }}</span>
              <span class="size-info">大小: {{ formatBytes(getByteLength(inputJson)) }}</span>
              <span class="status-info" :class="statusClass">{{ statusText }}</span>
            </div>
          </div>
        </div>

        <!-- 操作按钮区域 -->
        <div class="operation-section">
          <div class="btn-group">
            <el-button type="primary" @click="formatJson" :loading="processing" :disabled="!inputJson.trim()">
              <el-icon><Operation /></el-icon>
              格式化
            </el-button>
            <el-button type="success" @click="compressJson" :loading="processing" :disabled="!inputJson.trim()">
              <el-icon><Rank /></el-icon>
              压缩
            </el-button>
            <el-button type="warning" @click="repairJson" :loading="processing" :disabled="!inputJson.trim()">
              <el-icon><Tools /></el-icon>
              智能修复
            </el-button>
            <el-button @click="validateJson" :disabled="!inputJson.trim()">
              <el-icon><CircleCheck /></el-icon>
              校验
            </el-button>
            <el-button @click="swapContent" :disabled="!inputJson && !outputJson">
              <el-icon><Switch /></el-icon>
              交换内容
            </el-button>
            <el-button @click="clearAll">
              <el-icon><Delete /></el-icon>
              清空
            </el-button>
          </div>
        </div>

        <!-- 输出区域 -->
        <div class="output-section">
          <h3 class="section-title">
            <el-icon><View /></el-icon>
            格式化结果
            <span v-if="outputJson" class="result-info">({{ outputJson.split("\n").length }}行)</span>
          </h3>
          <div class="output-container">
            <el-input type="textarea" :rows="12" placeholder="格式化结果将在这里显示..." v-model="outputJson" readonly />
            <div class="output-actions" v-if="outputJson">
              <el-button size="small" @click="copyResult">
                <el-icon><CopyDocument /></el-icon>
                复制结果
              </el-button>
              <el-button size="small" @click="downloadResult">
                <el-icon><Download /></el-icon>
                下载JSON
              </el-button>
              <el-button size="small" @click="generateSchema" v-if="isValidJson">
                <el-icon><Document /></el-icon>
                生成Schema
              </el-button>
            </div>
          </div>
        </div>

        <!-- 配置选项 -->
        <div class="config-section">
          <h3 class="section-title">
            <el-icon><Setting /></el-icon>
            格式化配置
          </h3>
          <el-row :gutter="16">
            <el-col :span="8">
              <el-form-item label="缩进大小:">
                <el-select v-model="formatConfig.indent" style="width: 100%">
                  <el-option label="2个空格" :value="2" />
                  <el-option label="4个空格" :value="4" />
                  <el-option label="Tab缩进" value="tab" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="排序方式:">
                <el-select v-model="formatConfig.sortKeys" style="width: 100%">
                  <el-option label="保持原序" :value="false" />
                  <el-option label="按键排序" :value="true" />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="修复模式:">
                <el-select v-model="repairConfig.mode" style="width: 100%">
                  <el-option label="智能修复" value="smart" />
                  <el-option label="严格模式" value="strict" />
                  <el-option label="宽松模式" value="loose" />
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
        </div>

        <!-- 错误信息显示 -->
        <div class="error-section" v-if="errorInfo.hasError">
          <el-alert :title="errorInfo.title" :type="errorInfo.type" :closable="false" show-icon>
            <template #default>
              <div class="error-content">
                <p><strong>错误信息:</strong> {{ errorInfo.message }}</p>
                <p v-if="errorInfo.line"><strong>错误位置:</strong> 第{{ errorInfo.line }}行，第{{ errorInfo.column }}列</p>
                <p v-if="errorInfo.suggestion"><strong>修复建议:</strong> {{ errorInfo.suggestion }}</p>
              </div>
            </template>
          </el-alert>
        </div>

        <!-- 使用说明 -->
        <div class="info-section">
          <el-alert title="功能说明" type="info" :closable="false" show-icon>
            <template #default>
              <ul class="info-list">
                <li><strong>格式化</strong>：将压缩的JSON转换为易读的格式，支持自定义缩进</li>
                <li><strong>压缩</strong>：去除多余空格和换行，最小化JSON体积</li>
                <li><strong>智能修复</strong>：自动修复常见JSON格式错误，支持多种修复模式</li>
                <li><strong>格式校验</strong>：检查JSON语法正确性，提供详细错误信息</li>
                <li><strong>Schema生成</strong>：根据JSON数据自动生成JSON Schema结构</li>
              </ul>
            </template>
          </el-alert>
        </div>
      </div>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="drawerVisible = false">关闭</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts" name="JsonFormatter">
import { ref, reactive, computed } from "vue";
import { ElMessage } from "element-plus";
import {
  EditPen,
  View,
  Operation,
  Rank,
  Tools,
  CircleCheck,
  Switch,
  Delete,
  CopyDocument,
  Download,
  Document,
  Setting
} from "@element-plus/icons-vue";

interface DrawerProps {}

interface FormatConfig {
  indent: number | string;
  sortKeys: boolean;
}

interface RepairConfig {
  mode: "smart" | "strict" | "loose";
}

interface ErrorInfo {
  hasError: boolean;
  type: "error" | "warning" | "success";
  title: string;
  message: string;
  line?: number;
  column?: number;
  suggestion?: string;
}

const drawerVisible = ref(false);
const drawerProps = ref<DrawerProps>({});
const inputJson = ref("");
const outputJson = ref("");
const processing = ref(false);
const maxLength = 100000; // 最大字符限制

// 配置选项
const formatConfig = reactive<FormatConfig>({
  indent: 2,
  sortKeys: false
});

const repairConfig = reactive<RepairConfig>({
  mode: "smart"
});

// 错误信息
const errorInfo = reactive<ErrorInfo>({
  hasError: false,
  type: "error",
  title: "",
  message: "",
  line: undefined,
  column: undefined,
  suggestion: undefined
});

// 计算属性
const isValidJson = computed(() => {
  try {
    if (!inputJson.value.trim()) return false;
    JSON.parse(inputJson.value.trim());
    return true;
  } catch {
    return false;
  }
});

const statusClass = computed(() => {
  if (!inputJson.value.trim()) return "status-empty";
  return isValidJson.value ? "status-valid" : "status-invalid";
});

const statusText = computed(() => {
  if (!inputJson.value.trim()) return "等待输入";
  return isValidJson.value ? "格式正确" : "格式错误";
});

// 工具函数
const getByteLength = (str: string): number => {
  return new Blob([str]).size;
};

const formatBytes = (bytes: number): string => {
  if (bytes === 0) return "0 B";
  const k = 1024;
  const sizes = ["B", "KB", "MB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i];
};

// 清除错误信息
const clearError = () => {
  errorInfo.hasError = false;
  errorInfo.message = "";
  errorInfo.line = undefined;
  errorInfo.column = undefined;
  errorInfo.suggestion = undefined;
};

// 设置错误信息
const setError = (message: string, type: "error" | "warning" = "error", line?: number, column?: number, suggestion?: string) => {
  errorInfo.hasError = true;
  errorInfo.type = type;
  errorInfo.title = type === "error" ? "JSON格式错误" : "JSON格式警告";
  errorInfo.message = message;
  errorInfo.line = line;
  errorInfo.column = column;
  errorInfo.suggestion = suggestion;
};

// 输入变化处理
const onInputChange = () => {
  clearError();
  if (!inputJson.value.trim()) {
    outputJson.value = "";
    return;
  }

  // 实时验证
  try {
    JSON.parse(inputJson.value.trim());
  } catch (error: any) {
    const match = error.message.match(/position (\d+)/);
    if (match) {
      const position = parseInt(match[1]);
      const lines = inputJson.value.substring(0, position).split("\n");
      const line = lines.length;
      const column = lines[lines.length - 1].length + 1;
      setError(error.message, "error", line, column);
    } else {
      setError(error.message, "error");
    }
  }
};

// JSON格式化
const formatJson = async () => {
  if (!inputJson.value.trim()) {
    ElMessage({
      message: "请输入JSON字符串",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  processing.value = true;
  clearError();

  try {
    let parsed = JSON.parse(inputJson.value.trim());

    // 是否需要排序键
    if (formatConfig.sortKeys) {
      parsed = sortObjectKeys(parsed);
    }

    // 格式化缩进
    const indentValue = formatConfig.indent === "tab" ? "\t" : formatConfig.indent;
    const formatted = JSON.stringify(parsed, null, indentValue);

    outputJson.value = formatted;
    ElMessage({
      message: "JSON格式化成功",
      type: "success",
      zIndex: 3000,
      duration: 3000
    });
  } catch (error: any) {
    handleJsonError(error);
  } finally {
    processing.value = false;
  }
};

// JSON压缩
const compressJson = async () => {
  if (!inputJson.value.trim()) {
    ElMessage({
      message: "请输入JSON字符串",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  processing.value = true;
  clearError();

  try {
    const parsed = JSON.parse(inputJson.value.trim());
    const compressed = JSON.stringify(parsed);

    outputJson.value = compressed;
    const savedBytes = getByteLength(inputJson.value) - getByteLength(compressed);
    ElMessage({
      message: `JSON压缩成功，节省了 ${formatBytes(savedBytes)}`,
      type: "success",
      zIndex: 3000,
      duration: 3000
    });
  } catch (error: any) {
    handleJsonError(error);
  } finally {
    processing.value = false;
  }
};

// 智能修复JSON
const repairJson = async () => {
  if (!inputJson.value.trim()) {
    ElMessage({
      message: "请输入需要修复的JSON字符串",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  processing.value = true;
  clearError();

  try {
    let repaired = inputJson.value.trim();

    // 基础修复
    repaired = basicJsonRepair(repaired);

    // 根据模式进行不同程度的修复
    switch (repairConfig.mode) {
      case "loose":
        repaired = looseJsonRepair(repaired);
        break;
      case "smart":
        repaired = smartJsonRepair(repaired);
        break;
      case "strict":
        // 严格模式只做基础修复
        break;
    }

    // 验证修复结果
    const parsed = JSON.parse(repaired);
    const formatted = JSON.stringify(parsed, null, formatConfig.indent === "tab" ? "\t" : formatConfig.indent);

    outputJson.value = formatted;
    ElMessage({
      message: "JSON修复成功",
      type: "success",
      zIndex: 3000,
      duration: 3000
    });
  } catch (error: any) {
    setError(`修复失败: ${error.message}`, "error", undefined, undefined, "请检查输入内容是否为有效的JSON结构");
    ElMessage({
      message: "JSON修复失败，请检查输入格式",
      type: "error",
      zIndex: 3000,
      duration: 4000
    });
  } finally {
    processing.value = false;
  }
};

// 基础JSON修复
const basicJsonRepair = (json: string): string => {
  let repaired = json;

  // 移除注释 (// 和 /* */)
  repaired = repaired.replace(/\/\/.*$/gm, "");
  repaired = repaired.replace(/\/\*[\s\S]*?\*\//g, "");

  // 修复尾随逗号
  repaired = repaired.replace(/,(\s*[}\]])/g, "$1");

  // 修复单引号为双引号
  repaired = repaired.replace(/'([^'\\]*(\\.[^'\\]*)*)'/g, '"$1"');

  // 修复属性名没有引号的情况
  repaired = repaired.replace(/([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g, '$1"$2":');

  return repaired;
};

// 宽松模式修复
const looseJsonRepair = (json: string): string => {
  let repaired = basicJsonRepair(json);

  // 尝试修复缺失的引号
  repaired = repaired.replace(/:\s*([a-zA-Z_$][a-zA-Z0-9_$]*)\s*([,}\]])/g, ': "$1"$2');

  // 修复undefined为null
  repaired = repaired.replace(/:\s*undefined\s*([,}\]])/g, ": null$1");

  // 修复函数引用
  repaired = repaired.replace(/:\s*function\s*\([^)]*\)\s*\{[^}]*\}\s*([,}\]])/g, ": null$1");

  return repaired;
};

// 智能模式修复
const smartJsonRepair = (json: string): string => {
  let repaired = looseJsonRepair(json);

  // 智能补全缺失的大括号
  const openBraces = (repaired.match(/\{/g) || []).length;
  const closeBraces = (repaired.match(/\}/g) || []).length;
  if (openBraces > closeBraces) {
    repaired += "}".repeat(openBraces - closeBraces);
  }

  // 智能补全缺失的方括号
  const openBrackets = (repaired.match(/\[/g) || []).length;
  const closeBrackets = (repaired.match(/\]/g) || []).length;
  if (openBrackets > closeBrackets) {
    repaired += "]".repeat(openBrackets - closeBrackets);
  }

  // 修复缺失的逗号
  repaired = repaired.replace(/("\s*)\s*\n\s*"/g, '$1,\n"');
  repaired = repaired.replace(/(\})\s*\n\s*\{/g, "$1,\n{");

  return repaired;
};

// 排序对象键
const sortObjectKeys = (obj: any): any => {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(sortObjectKeys);
  }

  const sortedKeys = Object.keys(obj).sort();
  const sortedObj: any = {};

  for (const key of sortedKeys) {
    sortedObj[key] = sortObjectKeys(obj[key]);
  }

  return sortedObj;
};

// 处理JSON错误
const handleJsonError = (error: any) => {
  const message = error.message;

  // 尝试解析错误位置
  const positionMatch = message.match(/position (\d+)/);
  if (positionMatch) {
    const position = parseInt(positionMatch[1]);
    const lines = inputJson.value.substring(0, position).split("\n");
    const line = lines.length;
    const column = lines[lines.length - 1].length + 1;

    let suggestion = "";
    if (message.includes("Unexpected token")) {
      suggestion = "检查是否有多余的逗号、引号或括号";
    } else if (message.includes("Unexpected end")) {
      suggestion = "检查是否缺少闭合的引号、括号或大括号";
    }

    setError(message, "error", line, column, suggestion);
  } else {
    setError(message, "error");
  }

  ElMessage({
    message: "JSON解析失败",
    type: "error",
    zIndex: 3000,
    duration: 4000
  });
};

// 校验JSON
const validateJson = () => {
  if (!inputJson.value.trim()) {
    ElMessage({
      message: "请输入JSON字符串",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  try {
    JSON.parse(inputJson.value.trim());
    clearError();
    ElMessage({
      message: "JSON格式正确",
      type: "success",
      zIndex: 3000,
      duration: 3000
    });
  } catch (error: any) {
    handleJsonError(error);
  }
};

// 交换内容
const swapContent = () => {
  const temp = inputJson.value;
  inputJson.value = outputJson.value;
  outputJson.value = temp;
  ElMessage({
    message: "内容已交换",
    type: "success",
    zIndex: 3000,
    duration: 2000
  });
};

// 清空所有内容
const clearAll = () => {
  inputJson.value = "";
  outputJson.value = "";
  clearError();
  ElMessage({
    message: "内容已清空",
    type: "success",
    zIndex: 3000,
    duration: 2000
  });
};

// 复制结果
const copyResult = async () => {
  if (!outputJson.value) {
    ElMessage({
      message: "没有可复制的内容",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  try {
    await navigator.clipboard.writeText(outputJson.value);
    ElMessage({
      message: "复制成功",
      type: "success",
      zIndex: 3000,
      duration: 2000
    });
  } catch (error) {
    // 降级方案
    const textArea = document.createElement("textarea");
    textArea.value = outputJson.value;
    document.body.appendChild(textArea);
    textArea.select();
    document.execCommand("copy");
    document.body.removeChild(textArea);
    ElMessage({
      message: "复制成功",
      type: "success",
      zIndex: 3000,
      duration: 2000
    });
  }
};

// 下载结果
const downloadResult = () => {
  if (!outputJson.value) {
    ElMessage({
      message: "没有可下载的内容",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  const blob = new Blob([outputJson.value], { type: "application/json;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = `formatted_json_${Date.now()}.json`;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
  ElMessage({
    message: "下载成功",
    type: "success",
    zIndex: 3000,
    duration: 2000
  });
};

// 生成JSON Schema
const generateSchema = () => {
  if (!isValidJson.value) {
    ElMessage({
      message: "请先输入有效的JSON",
      type: "warning",
      zIndex: 3000,
      duration: 3000
    });
    return;
  }

  try {
    const parsed = JSON.parse(inputJson.value.trim());
    const schema = generateJsonSchema(parsed);
    const formatted = JSON.stringify(schema, null, 2);

    outputJson.value = formatted;
    ElMessage({
      message: "JSON Schema生成成功",
      type: "success",
      zIndex: 3000,
      duration: 3000
    });
  } catch (error) {
    ElMessage({
      message: "Schema生成失败",
      type: "error",
      zIndex: 3000,
      duration: 3000
    });
  }
};

// 生成JSON Schema的辅助函数
const generateJsonSchema = (obj: any): any => {
  if (obj === null) {
    return { type: "null" };
  }

  const type = Array.isArray(obj) ? "array" : typeof obj;

  switch (type) {
    case "string":
      return { type: "string" };
    case "number":
      return { type: "number" };
    case "boolean":
      return { type: "boolean" };
    case "array":
      const items = obj.length > 0 ? generateJsonSchema(obj[0]) : { type: "string" };
      return {
        type: "array",
        items
      };
    case "object":
      const properties: any = {};
      const required: string[] = [];

      for (const [key, value] of Object.entries(obj)) {
        properties[key] = generateJsonSchema(value);
        required.push(key);
      }

      return {
        type: "object",
        properties,
        required
      };
    default:
      return { type: "string" };
  }
};

// 接收父组件传过来的参数
const acceptParams = async (params: DrawerProps) => {
  drawerProps.value = params;
  drawerVisible.value = true;
  // 重置表单
  inputJson.value = "";
  outputJson.value = "";
  clearError();
};

defineExpose({
  acceptParams
});
</script>

<style lang="scss" scoped>
.json-formatter-form {
  display: flex;
  flex-direction: column;
  gap: 24px;
  .input-section,
  .output-section,
  .config-section {
    .section-title {
      display: flex;
      gap: 8px;
      align-items: center;
      margin: 0 0 16px;
      font-size: 16px;
      font-weight: 600;
      color: var(--el-text-color-primary);
      .el-icon {
        color: var(--el-color-primary);
      }
      .result-info {
        font-size: 14px;
        font-weight: normal;
        color: var(--el-text-color-regular);
      }
    }
  }
  .input-section,
  .config-section {
    padding: 20px;
    background: var(--el-bg-color-page);
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 8px;
  }
  .input-container,
  .output-container {
    position: relative;
    .input-info {
      display: flex;
      gap: 16px;
      margin-top: 8px;
      font-size: 12px;
      .char-count,
      .size-info {
        padding: 2px 8px;
        color: var(--el-text-color-secondary);
        background: var(--el-fill-color-light);
        border-radius: 4px;
      }
      .status-info {
        padding: 2px 8px;
        font-weight: 500;
        border-radius: 4px;
        &.status-empty {
          color: var(--el-text-color-placeholder);
          background: var(--el-fill-color-light);
        }
        &.status-valid {
          color: var(--el-color-success);
          background: var(--el-color-success-light-9);
        }
        &.status-invalid {
          color: var(--el-color-danger);
          background: var(--el-color-danger-light-9);
        }
      }
    }
    .output-actions {
      display: flex;
      gap: 8px;
      margin-top: 8px;
    }
  }
  .operation-section {
    display: flex;
    justify-content: center;
    padding: 20px;
    background: var(--el-bg-color-page);
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 8px;
    .btn-group {
      display: flex;
      flex-wrap: wrap;
      gap: 12px;
      justify-content: center;
    }
  }
  .error-section {
    .error-content {
      p {
        margin: 4px 0;
        font-size: 13px;
        line-height: 1.5;
        strong {
          color: var(--el-text-color-primary);
        }
      }
    }
  }
  .info-section {
    .info-list {
      padding-left: 20px;
      margin: 8px 0 0;
      li {
        margin-bottom: 6px;
        font-size: 13px;
        line-height: 1.5;
        strong {
          color: var(--el-color-primary);
        }
      }
    }
  }
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
}

// 响应式设计
@media (width <= 768px) {
  .json-formatter-form {
    gap: 16px;
    .input-section,
    .config-section {
      padding: 16px;
    }
    .operation-section {
      padding: 16px;
      .btn-group {
        gap: 8px;
        .el-button {
          flex: 1;
          min-width: 0;
        }
      }
    }
    .input-container,
    .output-container {
      .input-info {
        flex-direction: column;
        gap: 8px;
      }
      .output-actions {
        flex-direction: column;
        .el-button {
          width: 100%;
        }
      }
    }
  }
}
</style>

<!-- 全局样式，确保消息显示在弹窗之上 -->
<style>
/* 确保ElMessage组件显示在最顶层 */
.el-message {
  z-index: 3001 !important;
}

/* 确保消息类型的样式优先级 */
.el-message.el-message--success,
.el-message.el-message--warning,
.el-message.el-message--error,
.el-message.el-message--info {
  z-index: 3001 !important;
}
</style>
